package org.example.aigc.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;


import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.servlet.ServletOutputStream;


import jakarta.servlet.http.HttpServletRequest;
import org.example.aigc.entity.*;
import org.example.aigc.mapper.*;
import org.example.aigc.service.CourseService;
import org.example.aigc.utils.Reply;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;

@Service
public class CourseServiceImpl implements CourseService {

    private final CourseMapper courseMapper;
    private final UploadMapper uploadMapper;
    private final FavoriteMapper favoriteMapper;
    private final TeacherMapper teacherMapper;
    private final PartMapper partMapper;
    private final PPTMapper pptMapper;
    private final SectionMapper sectionMapper;
    private final AudioMapper audioMapper;
    private final AppearanceMapper appearanceMapper;
    private final String avatarUploadDir;
    private final String pptUploadDir;
    private final String videoUploadDir;
    private final String url = "http://172.26.94.12:7861";
    private final RestTemplate restTemplate;

    @Autowired
    public CourseServiceImpl(
            CourseMapper courseMapper,
            FavoriteMapper favoriteMapper,
            UploadMapper uploadMapper,
            TeacherMapper teacherMapper,
            PartMapper partMapper,
            SectionMapper sectionMapper,
            PPTMapper pptMapper,
            AudioMapper audioMapper,
            AppearanceMapper appearanceMapper,
            Environment environment,
            RestTemplate restTemplate) {
        this.courseMapper = courseMapper;
        this.favoriteMapper = favoriteMapper;
        this.uploadMapper = uploadMapper;
        this.teacherMapper = teacherMapper;
        this.partMapper = partMapper;
        this.sectionMapper = sectionMapper;
        this.pptMapper = pptMapper;
        this.audioMapper = audioMapper;
        this.appearanceMapper = appearanceMapper;
        this.avatarUploadDir = Objects.requireNonNull(environment.getProperty("resources.avatar-locations")).split(":", 2)[1];
        this.pptUploadDir = Objects.requireNonNull(environment.getProperty("resources.ppt-locations")).split(":", 2)[1];
        this.videoUploadDir = Objects.requireNonNull(environment.getProperty("resources.video-locations")).split(":", 2)[1];
        this.restTemplate = restTemplate;
    }

    public List<Course> getAllCourse() {
        return courseMapper.selectAll();
    }

    public Course getById(Long id) {
        return courseMapper.selectById(id);
    }

    public Boolean isFavorite(HttpServletRequest request, Long courseId) {
        User user = (User) request.getSession().getAttribute("user");
        // 用户未登录
        if (user == null) {
            return null;
        }
        return favoriteMapper.hasFavorite(user.getId(), courseId) != null;
    }

    public Reply createCourse(HttpServletRequest request, String courseName, String coverName, String detail, Long audioId, Long appearanceId) {
        // 获取用户信息
        User user = (User) request.getSession().getAttribute("user");
        if (user == null) {
            // 用户未登录
            return new Reply("上传课程 " + courseName).error(1, "用户未登录");
        }
        int identity = user.getIdentity();
        if (identity == 1) {
            // 用户不是教师
            return new Reply("上传课程 " + courseName).error(2, "用户不是教师");
        }
        Audio audio = audioMapper.selectById(audioId);
        if (audio == null) {
            return new Reply("上传课程 " + courseName).error(3, "音频模型未找到");
        }
        Appearance appearance = appearanceMapper.selectById(appearanceId);
        if (appearance == null) {
            return new Reply("上传课程 " + courseName).error(4, "虚拟教师形象模型未找到");
        }
        String knowledgeBaseName = UUID.randomUUID() + "";
        Teacher teacher = teacherMapper.selectByUserId(user.getId());
        Long teacherId = teacher.getId();
        Course course = new Course();
        course.setCourseName(courseName);
        course.setDetail(detail);
        course.setCoverName(coverName);
        course.setTeacher(teacher);
        course.setAudio(audio);
        course.setAppearance(appearance);
        course.setKnowledgeBaseName(knowledgeBaseName);
        // 插入课程数据
        courseMapper.insert(course);
        Long courseId = course.getId();
        if (courseId == null) {
            // 新建课程失败
            return new Reply("上传课程 " + courseName).error(5, "上传课程失败");
        }
        String URL = url + "/knowledge_base/create_knowledge_base";
        // 向后端发送请求
        JSONObject requestToLangchain = new JSONObject();
        // 请求体
        requestToLangchain.put("knowledge_base_name", knowledgeBaseName);
        requestToLangchain.put("vector_store_type", "faiss");
        requestToLangchain.put("embed_model", "bge-large-zh-v1.5");
        // 请求变量
        JSONObject result = restTemplate.postForObject(URL, requestToLangchain, JSONObject.class);
        if (result == null)
            return new Reply("上传课程 " + courseName).error(6, "知识库新建失败");
        uploadMapper.insert(teacherId, courseId);
        return new Reply("上传课程 " + courseName).ok(0, "成功").put("courseId", courseId);
    }

    public int deleteCourse(Long courseId) {
        Course course = courseMapper.selectById(courseId);
        if (course == null) {
            // 未查询到该课程
            return 1;
        }
        // 删除课程的部分
        partMapper.deleteByCourseId(courseId);
        // 查询课程包含的所有章节
        List<Section> sections = sectionMapper.selectByCourseId(courseId);
        // 删除章节
        sections.forEach((this::deleteSection));

        // 删除封面文件
        String coverPath = avatarUploadDir + course.getCoverName();
        File cover = new File(coverPath);
        if (cover.exists()) {
            boolean flag = cover.delete();
            if (!flag) {
                // 封面删除失败
                return 4;
            }
        } else {
            // 封面未找到
            return 3;
        }
        String knowledgeBaseName = course.getKnowledgeBaseName();
        String URL = url + "/knowledge_base/delete_knowledge_base";
        // 请求变量
        JSONObject result = restTemplate.postForObject(URL, knowledgeBaseName, JSONObject.class);
        if (result == null)
            //删除知识库失败
            return 5;
        // 删除数据库信息
        courseMapper.deleteById(courseId);
        uploadMapper.deleteByCourseId(courseId);
        return 0;
    }

    public List<Part> getPartByCourseId(Long id) {
        return partMapper.selectByCourseId(id);
    }

    public Reply createPart(String name, String chapter, Course course) {
        Part part = new Part();
        part.setName(name);
        part.setCourse(course);
        part.setChapter(chapter);
        partMapper.insert(part);
        Long partId = part.getId();
        if (partId == null) {
            // 新建部分失败
            return new Reply("创建部分 " + name).error(1, "失败");
        }

        return new Reply("创建部分 " + name).ok(0, "成功").put("partId", partId);
    }

    public int deletePart(Long partId) {
        partMapper.deleteById(partId);
        return 0;
    }

    public int updateDetail(HttpServletRequest request, Long courseId, String newDetail) {
        User user = (User) request.getSession().getAttribute("user");
        if (user == null) {
            // 用户未登录
            return 1;
        }
        int identity = user.getIdentity();
        if (identity == 1) {
            // 用户不是教师
            return 2;
        }
        Course course = courseMapper.selectById(courseId);
        if (course == null) {
            // 不存在课程
            return 3;
        }
        course.setDetail(newDetail);
        courseMapper.updateDetail(courseId, newDetail);
        return 0;
    }


    public List<Section> getSectionByPartId(Long partId) {
        return sectionMapper.selectByPartId(partId);
    }

    public int deleteSection(Long sectionId) {
        Section section = sectionMapper.selectById(sectionId);
        return deleteSection(section);
    }

    public int deleteSection(Section section) {
        String videoPath = videoUploadDir + section.getVideoName();
        File file = new File(videoPath);
        if (file.exists()) {
            boolean flag = file.delete();
            if (!flag) {
                // 视频删除失败
                return 3;
            }
        } else {
            // 视频信息错误
            return 4;
        }
        // 删除 PPT 信息
        int flag = deletePPT(section.getPpt().getId());
        if (flag != 0) return flag;
        sectionMapper.deleteById(section.getId());
        return 0;
    }

    public Reply createSection(String name, String videoName, String times, Long pptId, Long partId, Long courseId, String chapter) {
        Section section = new Section();
        Part part;
        if (partId == -1L) {
            part = new Part();
            part.setId(-1L);
        } else {
            part = partMapper.selectById(partId);
        }
        Course course = courseMapper.selectById(courseId);
        PPT ppt = pptMapper.selectById(pptId);
        section.setName(name);
        section.setChapter(chapter);
        section.setPart(part);
        section.setCourse(course);
        section.setPpt(ppt);
        section.setVideoName(videoName);
        section.setTimes(times);
        sectionMapper.insert(section);
        Long sectionId = section.getId();
        if (sectionId == null) {
            // 新建章节失败
            return new Reply("创建章节 " + name).error(1, "失败");
        }
        return new Reply("创建章节 " + name).ok(0, "成功").put("sectionId", sectionId);
    }

    public Reply createPPT(String pptName, String content, Long courseId) {
        String contentFileName = UUID.randomUUID() + ".txt";
        File contentFile = new File(pptUploadDir + contentFileName);
        byte[] b = content.getBytes();
        FileOutputStream fos;
        try {
            fos = new FileOutputStream(contentFile);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        try {
            fos.write(b, 0, b.length);
            fos.flush();
            fos.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        PPT ppt = new PPT();
        ppt.setContentFileName(contentFileName);
        ppt.setPptName(pptName);
        ppt.setContent(content);
        File PPT = new File(pptUploadDir + pptName);
        if (uploadFiles(PPT, courseId))
            return new Reply("创建PPT内容 ").error(1, "失败：ppt上传到知识库失败");
        if (uploadFiles(contentFile, courseId))
            return new Reply("创建PPT内容 ").error(1, "失败：content上传到知识库失败");
        pptMapper.insert(ppt);
        Long pptId = ppt.getId();
        if (pptId == null)
            return new Reply("创建PPT内容 ").error(2, "失败");
        else
            return new Reply("创建PPT内容 ").error(0, "成功").put("pptId", pptId);
    }

    public int deletePPT(Long pptId) {
        PPT ppt = pptMapper.selectById(pptId);
        File pptFile = new File(pptUploadDir + ppt.getPptName());
        File contentFile = new File(pptUploadDir + ppt.getContentFileName());
        if (pptFile.exists() || contentFile.exists()) {
            boolean flag = pptFile.delete() && contentFile.delete();
            if (!flag) {
                // ppt相关文件删除失败
                return 1;
            }
        } else {
            // 未找到ppt相关文件
            return 2;
        }
        pptMapper.deleteById(pptId);
        return 0;
    }

    private boolean uploadFiles(File file, Long courseId) {
        String URL = url + "/knowledge_base/upload_docs";
        FileSystemResource fileSystemResource = new FileSystemResource(file);
        try {
            // 组装请求信息
            MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
            Map<String, Object> map = new HashMap<>();
            // 将 knowledgeEntity 的属性转换为 Map
            map.put("files", fileSystemResource);
            map.put("knowledge_base_name", courseMapper.selectById(courseId).getKnowledgeBaseName());
            map.put("override", true);
            map.put("to_vector_store", true);
            map.put("chunk_size", 250);
            map.put("chunk_overlap", 50);
            map.put("zh_title_enhance", true);
            map.put("not_refresh_vs_cache", false);
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                param.add(entry.getKey(), entry.getValue());
            }
            HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(param);
            RestTemplate restTemplate = new RestTemplate();
            JSONObject response = restTemplate.postForObject(URL, httpEntity, JSONObject.class);
            return false;
        } catch (Exception e) {
            throw new RuntimeException("[发送POST请求错误：]" + e.getMessage());
        }
    }

    public String generateWord(String imageURL) throws IOException {
        String secretKey = "xzf7cKYOpLrfMLRS"; // 用于签名的密钥
        long expirationTimeMs = 10000; // 10s
        String apiKeyId = "edb2959a3bceb8240fa9a39f6d44f1c5"; // API Key 的 ID
        long currentTimestamp = System.currentTimeMillis(); // 当前时间戳
        // 设置头部
        Map<String, Object> header = new HashMap<>();
        header.put("alg","HS256");
        header.put("sign_type","SIGN");
        // 声明Token失效时间
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.SECOND,10);
        // 设置载荷
        Map<String, Object> payload = new HashMap<>();
        payload.put("api_key",apiKeyId);
        payload.put("exp",currentTimestamp+expirationTimeMs);
        payload.put("timestamp",currentTimestamp);
        // 生成Token
        String token = Jwts.builder()
                .setHeader(header)// 设置Header
                .setClaims(payload) // 设置载核
//              .setExpiration(instance.getTime())// 设置生效时间
                .signWith(SignatureAlgorithm.HS256,Base64.getUrlEncoder().encodeToString(secretKey.getBytes())) // 签名,这里采用私钥进行签名
                .compact();
//        System.out.println(token);
        // 创建 JSON 对象
        JSONObject jsonObject = new JSONObject();

        try {
            // 设置模型和消息数组
            jsonObject.put("model", "glm-4v");
            JSONArray messagesArray = new JSONArray();

            // 创建用户消息对象
            JSONObject userMessageObject = new JSONObject();
            userMessageObject.put("role", "user");

            // 创建内容数组
            JSONArray contentArray = new JSONArray();

            // 添加文本消息
            JSONObject textMessageObject = new JSONObject();
            textMessageObject.put("type", "text");
            textMessageObject.put("text", "这是一张ppt截图，适当拓展相关内容");

            // 添加图片消息
            JSONObject imageMessageObject = new JSONObject();
            imageMessageObject.put("type", "image_url");

            // 添加图片 URL
            JSONObject imageUrlObject = new JSONObject();
            imageUrlObject.put("url", imageURL);
            imageMessageObject.put("image_url", imageUrlObject);

            // 将文本消息和图片消息添加到内容数组
            contentArray.add(textMessageObject);
            contentArray.add(imageMessageObject);

            // 将内容数组添加到用户消息对象
            userMessageObject.put("content", contentArray);

            // 将用户消息对象添加到消息数组
            messagesArray.add(userMessageObject);

            // 将模型和消息数组添加到 JSON 对象
            jsonObject.put("messages", messagesArray);

        } catch (JSONException e) {
            e.printStackTrace();
        }
        System.out.println(jsonObject);
         //创建 URL 对象
        URL url = new URL("https://open.bigmodel.cn/api/paas/v4/chat/completions");
        // 打开连接
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        // 设置请求头
        connection.setRequestProperty("Authorization",token);
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setRequestProperty("Content-Type", "application/json");
        OutputStream os = connection.getOutputStream();
        StringBuffer bu = new StringBuffer();
        //写入参数
        String s = jsonObject.toString();
        os.write(s.getBytes());
        os.flush();
        os.close();
        //10.获取输入流
        InputStream is = connection.getInputStream();
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = is.read(bytes)) != -1) {
            String line = new String(bytes, 0, len, StandardCharsets.UTF_8);
            bu.append(line);
        }
        is.close();
        String data = bu.toString();
        JSONObject object = JSON.parseObject(data).getObject("choices", JSONArray.class).getJSONObject(0).getJSONObject("message");
        return object.getString("content");
    }
}
